package p20_mvc初体验;

import lombok.Data;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.core.MethodParameter;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.yaml.snakeyaml.Yaml;

import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义返回值解析器步骤:
 * 1.实现HandlerMethodReturnValueHandler
 * 2.添加到RequestMappingHandlerAdapter
 * 自定义参数解析器和返回值解析器可能会失效，原因是其他解析器会先生效，如果其他解析器成功解析了，我们自定义的就不会起作用了
 */
public class _4_返回值解析器 {
    public static void main(String[] args) throws Exception {
        //可以在浏览器上访问本机的8080端口看效果，看看自定义返回值处理器是否生效
        AnnotationConfigServletWebServerApplicationContext context =
                new AnnotationConfigServletWebServerApplicationContext(_1_DispatcherServlet初始化时机.class);
    }

    /**
     * 自定义返回值处理器，将标注了@Yml的控制器方法的返回值转为yml格式并返回
     */
    static class YmlReturnValueHandler implements HandlerMethodReturnValueHandler {
        //返回值为真，才执行后续操作，参数：方法的返回值类型
        @Override
        public boolean supportsReturnType(MethodParameter returnType) {
            //判断目标控制器方法是否加了@Yml注解
            return returnType.hasMethodAnnotation(Yml.class);
        }

        /**
         * supportsReturnType为true，就执行这个方法，参数:返回值，返回值类型，视图模型容器，webRequest(封装了请求和响应对象)
         * 在该方法内，往响应体写入内容
         */
        @Override
        public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
            //将控制器方法返回值转为yml格式字符串，并写入响应体
            String dump = new Yaml().dump(returnValue);
            HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
            response.setContentType("text/plain;charset=utf-8");
            response.getWriter().println(dump);

            //设置请求已经处理完毕，后续就不会走视图解析器了;否则后续还会走视图解析器
            mavContainer.setRequestHandled(true);
        }
    }

    /**
     * 自定义返回值解析器就使用了这个注解
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD})
    @interface Yml {
    }

    @Data
    public static class Person {
        private Integer id;
        private String name;
        private String ip;
    }
}
